#include "ercheng_and_pic.h"
#include "ui_ercheng_and_pic.h"
#include<physicaltools.h>
#include "qcustomplot.h" //应用图像生成类
#include <QScreen>

int k2;

ercheng_and_pic::ercheng_and_pic(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ercheng_and_pic)
{
    ui->setupUi(this);

    //获取设备屏幕大小
    QRect screenRect = QGuiApplication::primaryScreen()->geometry();
    //获取设备像素比
    int screenW = screenRect.width();
    int screenH = screenRect.height();
    this->move ((screenW - this->width())/2,(screenH - this->height())/2); //窗口居中显示

    on_n_confirm_clicked();
    on_data_n_returnPressed();//初始化防止点击多次显示结果的情况发生

    setAttribute(Qt::WA_DeleteOnClose); //保证子窗口析构函数运行
}

ercheng_and_pic::~ercheng_and_pic()
{
    delete ui;

    //删除Qlist占用的内存及清空列表
    qDeleteAll(datalist_x);
    datalist_x.clear();
    qDeleteAll(datalist_y);
    datalist_y.clear();
    qDeleteAll(datanamelist);
    datanamelist.clear();
}

void ercheng_and_pic::on_pushButton_clicked()
{
    //绘图前先清除
       ui->customPlot->clearGraphs();//清除图像，函数接受一个int类型的返回值，返回删除的graphs数。
       ui->customPlot->legend->setVisible(false);//设置图例为不可见
       ui->customPlot->replot();//重新绘制

       QCPAxis *xAxis = ui->customPlot->xAxis;//x轴
       QCPAxis *yAxis = ui->customPlot->yAxis;//y轴

       ui->customPlot->addGraph(xAxis,yAxis);//设置图像坐标轴
       QVector<double> x(k2), y(k2); //初始化向量x和y

       for(int i = 0;i < k2;i ++){
           x[i] = datalist_x.at(i)->text().toDouble();
           y[i] = datalist_y.at(i)->text().toDouble();
       }
       ui->customPlot->graph(0)->setData(x, y);
       ui->customPlot->graph(0)->setName("散点图");// 设置图例名称
       ui->customPlot->legend->setBrush(QColor(255,255,255,0));//设置图例背景

       // 为坐标轴添加标签
       xAxis->setLabel("X轴");
       yAxis->setLabel("Y轴");

       // 设置坐标轴的范围，以看到所有数据
       ui->customPlot->graph(0)->rescaleAxes();
       ui->customPlot->legend->setVisible(true); // 显示图例
       ui->customPlot->graph(0)->setLineStyle((QCPGraph::LineStyle)0);  // 线段风格(QCPGraph::LineStyle)i
       ui->customPlot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle,QColor(qBlue(200)),5));//设置散点形状

       // 支持鼠标拖拽轴的范围、滚动缩放轴的范围，左键点选图层（每条曲线独占一个图层）
       ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);

       // 重画图像
       ui->customPlot->replot();

}

void ercheng_and_pic::on_back_clicked()//返回按钮
{
    physicaltools *fater = new physicaltools();
    this->close();
    fater->show();
}

void ercheng_and_pic::on_pushButton_2_clicked() //最小二乘法拟合
{
        int N = ui->N_ci->text().toInt();
        //参考C++最小二乘拟合 (高阶最小二乘拟合)（附C++代码）作者：koko_TT
        QVector<double> x(k2), y(k2); //初始化向量x和y

        for(int i = 0;i < k2;i ++){
            x[i] = datalist_x.at(i)->text().toDouble();
            y[i] = datalist_y.at(i)->text().toDouble();
        }
        Eigen::MatrixXd A(x.size(), N + 1);
        for (unsigned int i = 0; i < x.size(); ++i) {  // 遍历所有点

            for (int n = N, dex = 0; n >= 1; --n, ++dex) {  // 遍历N到1阶
                A(i, dex) = pow(x[i], n);
            }

            A(i, N) = 1;  //
        }
        // 创建B矩阵
        Eigen::MatrixXd B(y.size(), 1);

        for (int i = 0; i < y.size(); ++i) {
            B(i, 0) = y[i];
        }

        Eigen::MatrixXd W;
        W = (A.transpose() * A).inverse() * A.transpose() * B;
        double w[N+1];
        for(int i = 0;i <= N;i++)
        {
            w[i] = W(i,0);
        }//矩阵计算完毕

        QString res;
        res += "y=";
        QVector<double> x_fit(k2), y_fit(k2); //初始化向量x_fit和y_fit
        for (int i=0; i<k2; ++i)
        {
            x_fit[i] = x[i];
            for (int n = N; n >= 1; --n) // 遍历N到1阶
            {
                y_fit[i] = y_fit[i] + w[N-n]*pow(x[i], n);
            }
            y_fit[i] = y_fit[i]+w[N];
        }
        for(int i = N;i >= 2;i --)
        {
            res += QString::number(w[N-i],10,3);
            res+="x^";
            res+=QString::number(i);
            res+="+";
            if((N-i)%3==0) res+='\n';
        }

        res+=QString::number(w[N-1],10,3);
        res+="x+";
        res+=QString::number(w[N],10,3);
        ui->res_shizi->setText(res);
        ui->res_shizi->show();
        //绘图前先清除
        ui->customPlot->clearGraphs();//清除图像，函数接受一个int类型的返回值，返回删除的graphs数。
        ui->customPlot->legend->setVisible(false);//设置图例为不可见
        ui->customPlot->replot();//重新绘制

        QCPAxis *xAxis = ui->customPlot->xAxis;//x轴
        QCPAxis *yAxis = ui->customPlot->yAxis;//y轴

        // 为坐标轴添加标签
        xAxis->setLabel("X轴");
        yAxis->setLabel("Y轴");
        ui->customPlot->addGraph(xAxis,yAxis);//设置图像坐标轴
        ui->customPlot->graph(0)->setData(x, y);
        ui->customPlot->graph(0)->setName("散点图");// 设置图例名称
        ui->customPlot->legend->setBrush(QColor(255,255,255,0));//设置图例背景

        // 设置坐标轴的范围，以看到所有数据
        ui->customPlot->graph(0)->rescaleAxes();
        ui->customPlot->legend->setVisible(true); // 显示图例
        ui->customPlot->graph(0)->setLineStyle((QCPGraph::LineStyle)0);  // 线段风格(QCPGraph::LineStyle)i
        ui->customPlot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle,QColor(qBlue(200)),5));//设置散点形状

        ui->customPlot->addGraph(xAxis,yAxis);
        ui->customPlot->graph(1)->setData(x_fit, y_fit);
        ui->customPlot->graph(1)->setName("曲线拟合后");// 设置图例名称
        ui->customPlot->legend->setVisible(true); // 显示图例
        // 设置坐标轴的范围，以看到所有数据
        ui->customPlot->graph(1)->rescaleAxes(true);
        ui->customPlot->graph(1)->setPen(QPen(QColor(255, 0, 0)));       // 设置画笔
        ui->customPlot->graph(1)->setLineStyle((QCPGraph::LineStyle)1);  // 线段风格(QCPGraph::LineStyle)i
        // 支持鼠标拖拽轴的范围、滚动缩放轴的范围，左键点选图层（每条曲线独占一个图层）
        ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
        // 重画图像
        ui->customPlot->replot();
}

void ercheng_and_pic::createtest()
{
    for(int i=0;i<k2;i++)
    {
        data_x=new QLineEdit(this);
        //设置输入框在主对话框的位置
        data_x->setGeometry(60,150+28*i,75,25);
        //设置数据对象名字
        data_x->setObjectName("data"+QString::number(i));
        //向QList添加成员项
        datalist_x.append(data_x);
        //关联信号槽函数
        //connect(datalist_x.at(i),SIGNAL(clicked()),this,SLOT(slotButtonClicked()));
        data_x->show();

        data_y=new QLineEdit(this);
        //设置输入框在主对话框的位置
        data_y->setGeometry(180,150+28*i,75,25);
        //设置数据对象名字
        data_y->setObjectName("data"+QString::number(i));
        //向QList添加成员项
        datalist_y.append(data_y);
        //关联信号槽函数
        //connect(datalist_y.at(i),SIGNAL(clicked()),this,SLOT(slotButtonClicked()));
        data_y->show();

        //qDebug() << ui->data1->text().toInt();
        dataname=new QLabel(this);
        //设置输入框在主对话框的位置
        dataname->setGeometry(10,150+28*i,50,25);
        //设置数据对象名字
        dataname->setText("数据"+QString::number(i+1));
        datanamelist.append(dataname);
        dataname->show();
        //qDebug() << datalist.at(i)->text().toInt() << endl;
     }
}

void ercheng_and_pic::on_n_confirm_clicked()
{
    //删除Qlist占用的内存及清空列表
    qDeleteAll(datalist_x);
    datalist_x.clear();
    qDeleteAll(datalist_y);
    datalist_y.clear();
    qDeleteAll(datanamelist);
    datanamelist.clear();

    k2 = ui->data_n->text().toInt();
    connect(ui->n_confirm,&QPushButton::clicked,this,&ercheng_and_pic::createtest); //连接createtest函数动态创建文本框
}

void ercheng_and_pic::on_data_n_returnPressed()
{
    //删除Qlist占用的内存及清空列表
    qDeleteAll(datalist_x);
    datalist_x.clear();
    qDeleteAll(datalist_y);
    datalist_y.clear();
    qDeleteAll(datanamelist);
    datanamelist.clear();

    k2 = ui->data_n->text().toInt();
    connect(ui->data_n,&QLineEdit::returnPressed,this,&ercheng_and_pic::createtest); //连接createtest函数动态创建文本框
}

void ercheng_and_pic::on_pushButton_3_clicked()
{
    ercheng_and_pic *fater = new ercheng_and_pic();
    this->close();
    fater->show();
}

void ercheng_and_pic::on_import_2_clicked() //数据导入功能
{
    //删除Qlist占用的内存及清空列表
    qDeleteAll(datalist_x);
    datalist_x.clear();
    qDeleteAll(datalist_y);
    datalist_y.clear();
    qDeleteAll(datanamelist);
    datanamelist.clear();

    QString data_get;
    bool ok;
    data_get = QInputDialog::getText(this, tr("请输入你的数据"),tr("请输入数据"), QLineEdit::Normal,0, &ok);
    QStringList parts = data_get.split('\n');
    QString data_getx = parts.at(0), data_gety = parts.at(1);
    //data_getx.replace('','	');
    //data_gety.replace(' ','	');
    QStringList x_list = data_getx.split('	'),y_list = data_gety.split('	');
    qDebug() << x_list.size() << Qt::endl << y_list.size();
    if(x_list.size() == y_list.size()) k2 = y_list.size();

    else {
        QMessageBox::critical(this, tr("危险弹窗"),  tr("您输入的数据错误，请重新输入或手动输入"));
        return;
    }
    createtest();
    for (int i = 0; i < k2; i++) {
        datalist_x.at(i)->setText(x_list[i]);        //设置数据
        datalist_y.at(i)->setText(y_list[i]);
    }
}

